## 4.2. Writing and Executing Scripts

Bear in mind that the CGI script must be executable in the opinion of your operating system. In order to test it, you can run it from the console with the same login that Apache uses. If you cannot, you have a problem that's signaled by disagreeable messages at the client end, plus equivalent stories in the log files on the server, such as:

>     You don't have permission to access /cgi-bin/mycgi on this server

You need to do either of the following:

- Use `ScriptAlias` in your host's Config file, pointing to a safe location outside your webspace. This makes for better security because the Bad Guys then cannot read your scripts and analyze them for holes. "Security by obscurity" is not a sound policy on its own, but it does no harm when added to more vigorous precautions.

- Use `Addhandler` or `Sethandler` to set a handler type of `cgi-script`. In this case, you put the CGI scripts in your document root.

If you have not used `ScriptAlias`, then `Options` `ExecCGI` must be `on`. It will normally be on by default. See the section Section 4.5, "Debugging Scripts", later in this chapter, for more information on fixing scripts.

To experiment, we have a simple test script, mycgi.cgi, in two locations: .../cgi-bin to test the first method above, and .../site.cgi/htdocs to test the second. When it works, we would write the script properly in C or Perl or whatever.

The script mycgi.cgi looks like this:

>     #!/bin/sh
>     echo "content-type: text/plain"
>     echo
>     echo "Have a nice day"

Under Win32, providing you want to run your script under COMMAND.COM and call it mycgi.bat, the script can be a little simpler than the Unix version -- it doesn't need the line that specifies the shell:

>     @echo off
>     echo "content-type: text/plain"
>     echo.
>     echo "Have a nice day"

The `@echo` `off` command turns off command-line echoing, which would otherwise completely destroy the output of the batch file. The slightly weird-looking "`echo.`" gives a blank line (a plain `echo` without a dot prints "`ECHO is off`").

If you are running a more exotic shell, like bash or perl, you need the `shebang' line at the top of the script to invoke it:

>     #!shell path
>     ...

A CGI script consists of headers and a body. Everything up to the first blank line (strictly speaking, CRLF CRLF, but Apache will tolerate LF LF) is header, and everything else is body. The lines of the header are separated by LF or CRLF. A list of possible headers is to be found in the draft CGI 1.1 specification, from which this is a quotation:

>     The CGI
>     header fields have the generic syntax:

>         generic-header = field-name ":" [ field-value ] NL
>         field-name     = 1*<any CHAR, excluding CTLs, SP and ":">
>         field-value    = *( field-content | LWSP )
>         field-content  = *( token | tspecial | quoted-string )
>        The field-name is not case sensitive; a NULL field value is equivalent to
>        the header field not being sent.

>        Content-Type
>               The Internet Media Type [9] of the entity body, which is to
>               be sent unmodified to the client.

>         Content-Type = "Content-Type" ":" media-type NL
>               This is actually an HTTP-Header rather than a CGI-header
>               field, but it is listed here because of its importance in the
>               CGI dialogue as a member of the "one of these is required"
>               set of header fields.

>        Location
>               This is used to specify to the server that the script is
>               returning a reference to a document rather than an actual
>               document.

>         Location         = "Location" ":"
>                            ( fragment-URI | rel-URL-abs-path ) NL
>         fragment-URI     = URI [ # fragmentid ]
>         URI              = scheme ":" *qchar
>         fragmentid       = *qchar
>         rel-URL-abs-path = "/" [ hpath ] [ "?" query-string ]
>         hpath            = fpsegment *( "/" psegment )
>         fpsegment        = 1*hchar
>         psegment         = *hchar
>         hchar            = alpha | digit | safe | extra
>                          | ":" | "@" | "& | "="

Our little script first tells Apache to use the sh shell and then specifies what type of data the content is, using the `Content-Type` header. This must be specified because:

- Apache can't tell from the filename (remember that for ordinary files, there's a host of ways of determining the content type, for example, the mime.types file or the `AddType` directive).

- The CGI script may want to decide on content type dynamically.

So, the script must send at least one header line: `Content-Type`. We set it to `text/plain` to get a nicely formatted output screen. Failure to include it results in an error message on the client, plus equivalent entries in the server log files:

>     The server encountered an internal error or misconfiguration and was unable to complete your request

Headers must be terminated by a blank line, hence the second `echo`.

We are going to call our script from one of the Butterthlies forms: form_summer.html. Depending on which location and calling method we use for the script, we need slightly different invocations in the form.

### 4.2.1. Script in cgi-bin

To steer incoming demands for the script to the right place (.../cgi-bin ), we need to edit our ... /site.cgi/conf/httpd.conf file so it looks like this:

>     User webuser
>     Group webgroup
>     ServerName www.butterthlies.com
>     DocumentRoot /usr/www/site.cgi/htdocs
>     ScriptAlias /cgi-bin /usr/www/cgi-bin

We need to edit the form .../site.cgi/htdocs/form_summmer.html so that the relevant line reads:

>     <!-- UNIX -->
>     <FORM METHOD=POST ACTION="cgi-bin/mycgi.cgi">
>     <!-- Win32 -->
>     <FORM METHOD=POST ACTION="cgi-bin/mycgi.bat">

Since CGI processing is on by default, this should work. When you submit the Butterthlies order form, and thereby invoke the CGI script named by `ACTION`, you are sent the message "Have a nice day."

You would probably want to proceed in this way, that is, putting the script in the cgi-bin directory, if you were offering a web site to the outside world and wanted to maximize your security.

### 4.2.2. Script in DocumentRoot

The other method is to put scripts in amongst the HTML files. You should only do this if you trust the authors of the site to write safe scripts (or not write them at all) since security is much reduced. Generally speaking, it is safer to use a separate directory for scripts, as explained previously. First, it means that people writing HTML can't accidentally or deliberately cause security breaches by including executable code in the web tree. Second, it makes life harder for the Bad Guys: often it is necessary to allow fairly wide access to the nonexecutable part of the tree, but more careful control can be exercised on the CGI directories.

But regardless of these good intentions, we put mycgi.cgi in .../site.cgi/htdocs. The Config file is now:

>     User webuser
>     Group webgroup
>     ServerName www.butterthlies.com
>     DocumentRoot /usr/www/site.cgi/htdocs
>     AddHandler cgi-script cgi

The `AddHandler` directive means that any document Apache comes across with the extension .cgi will be taken to be an executable script. We need the corresponding line in the form:

>     <!-- UNIX -->
>     <FORM METHOD=POST ACTION="mycgi.cgi">
>     <!-- WIN32 -->
>     <FORM METHOD=POST ACTION="mycgi.bat">

Again, if we access http://www.butterthlies.com/form_summer.html, we get the result described.

Copyright © 2001 O'Reilly & Associates. All rights reserved.